//敌人数量更新
function initEnemyNumber() {
  switch (true) {
    case grade < 5:
      commonNumber = calculateEnemyNumber(5);
      bubbleNumber = calculateEnemyNumber(-1);
      machineNumber = calculateEnemyNumber(-2);
      chargeNumber = calculateEnemyNumber(-3);
      tankNumber = calculateEnemyNumber(-3);
      boomNumber = calculateEnemyNumber(-5);
      trapNumber = calculateEnemyNumber(-5);
      missileNumber = calculateEnemyNumber(-3);
      break;
    case grade >= 5 && grade <= 10:
      commonNumber = calculateEnemyNumber(5);
      bubbleNumber = calculateEnemyNumber(-5);
      machineNumber = calculateEnemyNumber(-6);
      chargeNumber = calculateEnemyNumber(-7);
      tankNumber = calculateEnemyNumber(-8);
      boomNumber = calculateEnemyNumber(-9);
      trapNumber = calculateEnemyNumber(-10);
      missileNumber = calculateEnemyNumber(-6);
      break;
    case grade >= 10 && grade <= 15:
      commonNumber = calculateEnemyNumber(10);
      bubbleNumber = calculateEnemyNumber(-10);
      machineNumber = calculateEnemyNumber(-11);
      chargeNumber = calculateEnemyNumber(-12);
      tankNumber = calculateEnemyNumber(-13);
      boomNumber = calculateEnemyNumber(-14);
      trapNumber = calculateEnemyNumber(-15);
      missileNumber = calculateEnemyNumber(-11);
      break;
    case grade >= 15 && grade <= 30:
      commonNumber = calculateEnemyNumber(15);
      bubbleNumber = calculateEnemyNumber(-12);
      machineNumber = calculateEnemyNumber(-13);
      chargeNumber = calculateEnemyNumber(-14);
      tankNumber = calculateEnemyNumber(-15);
      boomNumber = calculateEnemyNumber(-19);
      trapNumber = calculateEnemyNumber(-20);
      missileNumber = calculateEnemyNumber(-13);
      break;
    case grade >= 30:
      commonNumber = calculateEnemyNumber(30);
      bubbleNumber = calculateEnemyNumber(-20);
      machineNumber = calculateEnemyNumber(-21);
      chargeNumber = calculateEnemyNumber(-22);
      tankNumber = calculateEnemyNumber(-23);
      boomNumber = calculateEnemyNumber(-24);
      trapNumber = calculateEnemyNumber(-25);
      missileNumber = calculateEnemyNumber(-21);
      break;
  }
}

//修改exp
function changeExp() {
  $("#exp").css({
    width:
      (100 * (score - calculateScore(grade))) /
        (calculateScore(grade + 1) - calculateScore(grade)) +
      "%",
  });
}

//修改血量
function changeBlood() {
  $("#blood").css({
    width: (100 * currentHP) / baseHP + "%",
  });
  $("#bloodNumber").text(currentHP + "/" + baseHP);
  $("#userBlood").css({
    width: (100 * currentHP) / baseHP + "%",
  });
  if (currentHP !== baseHP) {
    $(".user-blood-border").show();
  } else {
    $(".user-blood-border").hide();
  }
}

//播放攻击音效
function playStrikeAudio() {
  const strikeAudios = document.querySelectorAll(".strikeAudio");

  for (let i = 0; i < strikeAudios.length; i++) {
    if (strikeAudios[i].paused) {
      strikeAudios[i].play();
      return strikeAudios[i];
    }
  }
  return null;
}

//播放拾取音效
function playEatAudio() {
  const eatAudios = document.querySelectorAll(".eatAudio");

  for (let i = 0; i < eatAudios.length; i++) {
    if (eatAudios[i].paused) {
      eatAudios[i].play();
      return eatAudios[i];
    }
  }
  return null;
}

//计算等级
function calculateGrade(score) {
  if (score < resourceScore) return 0;

  let grade = 1;
  let requiredScore = resourceScore;
  let nextThreshold = requiredScore;
  let increment = resourceScore; // 初始增量

  while (true) {
    increment *= 1.1; // 每次增量是上次的1.5倍
    nextThreshold += increment;

    if (score >= nextThreshold) {
      grade++;
    } else {
      break;
    }
  }
  return grade;
}

// 计算分数
function calculateScore(grade) {
  if (grade === 0) return 0;
  if (grade === 1) return resourceScore;

  let score = resourceScore;
  let increment = resourceScore;

  for (let i = 2; i <= grade; i++) {
    increment *= 1.1;
    score += increment;
  }

  return Math.ceil(score);
}

//获取随机技能数组
function randomList(arr, num) {
  var tempArr = [];
  var resultArr = [];

  tempArr.push(...arr);

  //枪数量不超过4
  if (gunNumber === 4) {
    tempArr = tempArr.filter((f) => f.name !== "Gun");
  }

  num = tempArr.length < num ? tempArr.length : num;

  for (var i = 0; i < num; i++) {
    var randomIndex = Math.floor(Math.random() * tempArr.length);
    resultArr.push(tempArr[randomIndex]);
    tempArr.splice(randomIndex, 1);
  }
  console.log(resultArr);
  return resultArr.sort(() => Math.random() - 0.5);
}

//更新技能UI
function updateSkillUI(arr) {
  var divStr = "";

  if (grade % UPGRADE_FREQUENCY === 0) {
    divStr =
      '<div id="skillTitle" class="skill-title">Select an skill to upgrade</div>';
  } else {
    divStr =
      '<div id="skillTitle" class="skill-title">Select an attribute to upgrade</div>';
  }

  for (var i = 0; i < arr.length; i++) {
    if (i === 0) {
      divStr +=
        '<div class="skill-box skill-box-active">\n' +
        "            <div>" +
        arr[i].name +
        "</div>\n" +
        "            <div>+" +
        arr[i].number +
        "</div>\n" +
        "        </div>";
    } else {
      divStr +=
        '<div class="skill-box">\n' +
        "            <div>" +
        arr[i].name +
        "</div>\n" +
        "            <div>+" +
        arr[i].number +
        "</div>\n" +
        "        </div>";
    }
  }

  chooseSkill = arr[0];

  $("#skillPopupContent").empty();

  $("#skillPopupContent").append($(divStr));

  //绑定监听事件
  $(".skill-box").click(function () {
    $(".skill-box").removeClass("skill-box-active");
    $(this).addClass("skill-box-active");

    chooseSkill = {
      name: $(this).children().eq(0).text(),
      number: Number($(this).children().eq(1).text()),
    };
  });
}

//更新属性
function setNewSkill() {
  switch (chooseSkill.name) {
    case "Bounce":
      bounce += chooseSkill.number;
      break;
    case "Pierce":
      pierce += chooseSkill.number;
      break;
    case "Gun":
      gunNumber += chooseSkill.number;
      gunList = [];
      for (var i = 0; i < gunNumber; i++) {
        gunList.push(new Gun(0, 0, 6, dpr * 5, 60, 0, dpr * 180, 0));
      }
      break;
    case "Guard":
      guardNumber += chooseSkill.number;
      guardList = [];
      var radians = (2 * Math.PI) / guardNumber;
      for (var i = 0; i < guardNumber; i++) {
        guardList.push(
          new Guard(0, 0, dpr * 60, r / 2, 0.02, radians * i, "#000000", 2)
        );
      }
      break;
    case "HP":
      baseHP += chooseSkill.number;
      changeBlood();
      break;
    case "Damage":
      damage += chooseSkill.number / 100;
      break;
    case "Speed":
      speed += chooseSkill.number / 100;
      break;
    case "Attack Speed":
      attackSpeed += chooseSkill.number / 100;
      break;
    case "Life Steal":
      lifeSteal += chooseSkill.number / 100;
      break;
    case "Crit Chance":
      critChance += chooseSkill.number / 100;
      break;
    case "Dodge":
      dodge += chooseSkill.number / 100;
      break;
    case "Knockback":
      knockBack += chooseSkill.number;
      break;
    case "Attack Range":
      attackRange += chooseSkill.number / 100;
      break;
    case "Pickup Range":
      pickupRange += chooseSkill.number / 100;
      break;
  }
}

//判断是否升级
function determineUpgrade() {
  //根据等级获取当前敌人数据，对敌人数量进行修改
  initEnemyNumber();

  //判断是否升级
  if (calculateGrade(score) > grade) {
    grade = calculateGrade(score);
    $("#grade").text(grade);
    //默认每级提升8%伤害，提升2点生命值
    damage += 0.08;
    baseHP += 2;
    //判断升级是否是3的倍数
    if (grade % UPGRADE_FREQUENCY === 0) {
      //获取随机技能
      //弹射、穿透、gun++、guard++
      var currentSkillList = randomList(skillList, 4);
      updateSkillUI(currentSkillList);
      console.log(currentSkillList);
    } else {
      //获取随机属性
      //伤害、移速、攻速、暴击、闪避、击退、攻击范围、拾取范围
      var currentAttributeList = randomList(attributeList, 4);
      updateSkillUI(currentAttributeList);
      console.log(currentAttributeList);
    }
    console.log("commonNumber: " + commonNumber);
    console.log("bubbleNumber: " + bubbleNumber);
    console.log("machineNumber: " + machineNumber);
    console.log("chargeNumber: " + chargeNumber);
    console.log("tankNumber: " + tankNumber);
    console.log("boomNumber: " + boomNumber);
    console.log("trapNumber: " + trapNumber);
    console.log("missileumber: " + missileNumber);
    //升级后移除所有敌人和子弹
    enemyList = [];
    enemyBulletList = [];
    bulletList = [];

    isUpdate = true;

    //弹出属性选择模态框
    gameState = 4;
    updateStateUI();
  }
}

//更新属性UI
function updateGameData() {
  $("#score").text(score);
  $("#gun").text(gunList.length);
  $("#guard").text(guardList.length);
  $("#damage").text(Math.round((damage - 1) * 100));
  $("#lifeSteal").text(Math.round(lifeSteal * 100));
  $("#critChance").text(Math.round(critChance * 100));
  $("#dodge").text(Math.round(dodge * 100));
  $("#speed").text(Math.round((speed - 1) * 100));
  $("#attackSpeed").text(Math.round((attackSpeed - 1) * 100));
  $("#knockBack").text(knockBack);
  $("#bounce").text(bounce);
  $("#pierce").text(pierce);
  $("#attackRange").text(Math.round((attackRange - 1) * 100));
  $("#pickupRange").text(Math.round((pickupRange - 1) * 100));
}

//根据游戏状态修改UI
function updateStateUI() {
  if (gameState === 0) {
    $("#mask").show();
    $("#popup").show();
    $("#popupButton").text("START GAME");
    $("#popupButton-restart").hide();
    $(".popup-start").show();
    $(".popup-score").hide();
  } else if (gameState === 1) {
    $(".pause-icon").show();
    $(".play-icon").hide();
    $("#mask").hide();
    $("#popup").hide();
    $("#skillPopup").hide();
    $("#popupButton-restart").hide();
    //如果是重新开始
    if (
      $("#popupButton").text() === "START GAME" ||
      $("#popupButton").text() === "RESTART"
    ) {
      init();
      $("#popupButton").text("");
    }
    if (isUpdate) {
      //吸收材料
      absorbInterval = 300;

      changeBlood();

      //更新属性
      setNewSkill();

      isUpdate = false;
    }
  } else if (gameState === 2) {
    $(".pause-icon").hide();
    $(".play-icon").show();
    $("#mask").show();
    $("#popup").show();
    $(".popup-start").hide();
    $(".popup-score").show();
    $(".popup-end").text("Game Paused");
    $("#popupScore").text(score);
    $("#popupButton").text("CONTINUE");
    $("#popupButton-restart").show();
    //保存游戏记录
    saveGameState();
  } else if (gameState === 3) {
    $(".pause-icon").hide();
    $(".play-icon").show();
    $("#mask").show();
    $("#popup").show();
    $(".popup-start").hide();
    $(".popup-score").show();
    $(".popup-end").text("Game Over");
    $("#popupScore").text(score);
    $("#popupButton").text("RESTART");
    $("#popupButton-restart").hide();
    $("#speedBuffBox").hide();
    $("#attackSpeedBuffBox").hide();
    $("#pickupRangeBuffBox").hide();
    gameState = 0;
    //删除游戏记录
    removeGameState();
  } else if (gameState === 4) {
    //弹出技能选择模态框
    $("#mask").show();
    $("#skillPopup").show();
    //保存游戏记录
    saveGameState();
  }
}

function restartGame() {
  removeGameState();
  $(".pause-icon").show();
  $(".play-icon").hide();
  $("#mask").hide();
  $("#popup").hide();
  $("#skillPopup").hide();
  $("#popupButton-restart").hide();
  $("#speedBuffBox").hide();
  $("#attackSpeedBuffBox").hide();
  $("#pickupRangeBuffBox").hide();
  $("#popupButton").text("");
  gameState = 1
  init();
}

//保存游戏记录
function saveGameState() {
  var gameStateInfo = {};
  gameStateInfo.foodList = foodList;
  gameStateInfo.enemyList = enemyList;
  gameStateInfo.score = score;
  gameStateInfo.grade = grade;
  gameStateInfo.damage = damage;
  gameStateInfo.speed = speed;
  gameStateInfo.attackSpeed = attackSpeed;
  gameStateInfo.lifeSteal = lifeSteal;
  gameStateInfo.critChance = critChance;
  gameStateInfo.dodge = dodge;
  gameStateInfo.knockBack = knockBack;
  gameStateInfo.attackRange = attackRange;
  gameStateInfo.pickupRange = pickupRange;
  gameStateInfo.bounce = bounce;
  gameStateInfo.pierce = pierce;
  gameStateInfo.gunNumber = gunNumber;
  gameStateInfo.guardNumber = guardNumber;
  gameStateInfo.enemySpeed = enemySpeed;
  gameStateInfo.angle = angle;
  gameStateInfo.battlegroundX = battlegroundX;
  gameStateInfo.battlegroundY = battlegroundY;
  gameStateInfo.myX = myX;
  gameStateInfo.myY = myY;
  gameStateInfo.gunList = gunList;
  gameStateInfo.bulletList = bulletList;
  gameStateInfo.guardList = guardList;
  gameStateInfo.rokList = rokList;
  gameStateInfo.sparkList = sparkList;
  gameStateInfo.driftList = driftList;
  gameStateInfo.boomSparkList = boomSparkList;
  gameStateInfo.explosionList = explosionList;
  gameStateInfo.deductionList = deductionList;
  gameStateInfo.corpseList = corpseList;
  gameStateInfo.enemyBulletList = enemyBulletList;
  gameStateInfo.plantList = plantList;
  gameStateInfo.buffList = buffList;
  gameStateInfo.shape = shape;
  gameStateInfo.baseHP = baseHP;
  gameStateInfo.currentHP = currentHP;
  gameStateInfo.invincible = invincible;
  gameStateInfo.myDirection = myDirection;
  gameStateInfo.gameState = gameState;
  gameStateInfo.commonNumber = invincible;
  gameStateInfo.bubbleNumber = bubbleNumber;
  gameStateInfo.machineNumber = machineNumber;
  gameStateInfo.chargeNumber = chargeNumber;
  gameStateInfo.tankNumber = tankNumber;
  gameStateInfo.boomNumber = boomNumber;
  gameStateInfo.trapNumber = trapNumber;
  gameStateInfo.missileNumber = missileNumber;

  console.log(gameStateInfo);

  localStorage.setItem("gameStateInfo", JSON.stringify(gameStateInfo));
}

//删除游戏记录
function removeGameState() {
  localStorage.removeItem("gameStateInfo");
}

//修改游戏状态
function changeGameState(status) {
  gameState = status;
  updateStateUI();
}

//绘制
function drawFrame() {
  canvas.width = canvas.width; // 重新设置宽度
  canvas.height = canvas.height; // 重新设置高度
  drawRectangle(ctx);
  drawDrift(ctx);
  drawGrid(ctx);
  drawBoomSpark(ctx);
  drawPlant(ctx);
  drawBuff(ctx);
  drawFood(ctx);
  drawEnemy(ctx);
  drawGuard(ctx);
  drawMyself(ctx);
  drawRok(ctx);
  drawGun(ctx);
  drawBullet(ctx);
  drawSpark(ctx);
  drawExplosion(ctx);
  drawDeduction(ctx);
  drawCorpse(ctx);
  drawEnemyBullet(ctx);
  updateGameData();
}

//敌方数据升级
function enemyDataGrade(n) {
  return Math.ceil(n * (1 + grade / 15));
}

//生成敌人
function generateEnemy() {
  var commonEnemyListLength = enemyList.filter(
    (item) => item.type === "common"
  ).length;
  for (var i = 0; i < commonNumber - commonEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 150 ||
      Math.abs(randomY - myY) < dpr * 150
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new Enemy(
        generateID(),
        "common",
        randomX,
        randomY,
        r,
        enemyDataGrade(10),
        1,
        dpr * 0.5,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        0
      )
    );
  }

  var bubbleEnemyListLength = enemyList.filter(
    (item) => item.type === "bubble"
  ).length;

  for (var i = 0; i < bubbleNumber - bubbleEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 150 ||
      Math.abs(randomY - myY) < dpr * 150
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new BubbleEnemy(
        generateID(),
        "bubble",
        randomX,
        randomY,
        1.1 * r,
        enemyDataGrade(30),
        3,
        dpr * 0.3,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        0,
        50,
        enemyDataGrade(5)
      )
    );
  }

  var machineEnemyListLength = enemyList.filter(
    (item) => item.type === "machine"
  ).length;

  for (var i = 0; i < machineNumber - machineEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 150 ||
      Math.abs(randomY - myY) < dpr * 150
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new MachineEnemy(
        generateID(),
        "machine",
        randomX,
        randomY,
        1.2 * r,
        enemyDataGrade(40),
        3,
        dpr * 0.4,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        0,
        100,
        enemyDataGrade(2)
      )
    );
  }

  var chargeEnemyListLength = enemyList.filter(
    (item) => item.type === "charge"
  ).length;

  for (var i = 0; i < chargeNumber - chargeEnemyListLength; i++) {
    // for (var i = 0; i < 10 - chargeEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 150 ||
      Math.abs(randomY - myY) < dpr * 150
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new ChargeEnemy(
        generateID(),
        "charge",
        randomX,
        randomY,
        1.2 * r,
        enemyDataGrade(30),
        3,
        dpr * 0.5,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        0,
        50,
        enemyDataGrade(1),
        5,
        200
      )
    );
  }

  var tankEnemyListLength = enemyList.filter(
    (item) => item.type === "tank"
  ).length;

  for (var i = 0; i < tankNumber - tankEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 200 ||
      Math.abs(randomY - myY) < dpr * 200
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new TankEnemy(
        generateID(),
        "tank",
        randomX,
        randomY,
        1.5 * r,
        enemyDataGrade(150),
        5,
        dpr * 0.5,
        enemyDataGrade(5),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        10,
        0,
        0,
        0
      )
    );
  }

  var boomEnemyListLength = enemyList.filter(
    (item) => item.type === "boom"
  ).length;

  for (var i = 0; i < boomNumber - boomEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 250 ||
      Math.abs(randomY - myY) < dpr * 250
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new BoomEnemy(
        generateID(),
        "boom",
        randomX,
        randomY,
        1.2 * r,
        enemyDataGrade(240),
        5,
        dpr * 0.3,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        5,
        200,
        enemyDataGrade(8)
      )
    );
  }

  var trapEnemyListLength = enemyList.filter(
    (item) => item.type === "trap"
  ).length;

  for (var i = 0; i < trapNumber - trapEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于200
    while (
      Math.abs(randomX - myX) < dpr * 250 ||
      Math.abs(randomY - myY) < dpr * 250
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new TrapEnemy(
        generateID(),
        "trap",
        randomX,
        randomY,
        1.3 * r,
        enemyDataGrade(200),
        5,
        dpr * 0.6,
        enemyDataGrade(3),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        5,
        enemyDataGrade(2)
      )
    );
  }

  var missileEnemyListLength = enemyList.filter(
    (item) => item.type === "missile"
  ).length;

  for (var i = 0; i < missileNumber - missileEnemyListLength; i++) {
    var randomX = myX;
    var randomY = myY;
    //与玩家的距离不得小于250
    while (
      Math.abs(randomX - myX) < dpr * 250 ||
      Math.abs(randomY - myY) < dpr * 250
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    enemyList.push(
      new MissileEnemy(
        generateID(),
        "missile",
        randomX,
        randomY,
        1.2 * r,
        enemyDataGrade(30),
        5,
        dpr * 0.3,
        enemyDataGrade(2),
        0,
        "#000",
        0,
        0,
        0,
        "come",
        0,
        50,
        enemyDataGrade(5)
      )
    );
  }
}

//生成植物
function generatePlant() {
  if (plantInterval === 0) {
    var randomX = myX;
    var randomY = myY;
    while (
      Math.abs(randomX - myX) < dpr * 100 ||
      Math.abs(randomY - myY) < dpr * 100
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    plantList.push(new Plant(generateID(), randomX, randomY, 30));
    plantInterval = Math.round(1000 + Math.random() * 100);
  }
  plantInterval--;
}

//生成buff
function generateBuff() {
  if (Math.random() > 0.997) {
    var randomX = myX;
    var randomY = myY;
    while (
      Math.abs(randomX - myX) < dpr * 100 ||
      Math.abs(randomY - myY) < dpr * 100
    ) {
      randomX = Math.floor(Math.random() * battlegroundW) + battlegroundX;
      randomY = Math.floor(Math.random() * battlegroundH) + battlegroundY;
    }
    var type = buffTypeList[Math.floor(Math.random() * buffTypeList.length)];
    buffList.push(new Buff(randomX, randomY, 5, buffColor[type], type, 2500));
  }
}

//生成材料
function generateFood(object) {
  var foodW = dpr * (Math.random() * 2 + 8);
  var foodH = dpr * (Math.random() * 2 + 8);
  var foodRadius = dpr * (Math.random() * 2 + 1);
  var foodColor = "#000000";
  var deviation = 0;
  if (object.material > 1) {
    deviation = 10;
  }

  Array.from({ length: object.material }).forEach((_, index) => {
    if (Math.random() > 0.9) {
      foodColor = "red";
      foodList.push(
        new Food(
          randomOffset(object.x, dpr, deviation),
          randomOffset(object.y, dpr, deviation),
          foodW,
          foodH,
          foodRadius,
          Math.random() * 90,
          foodColor,
          1
        )
      );
    } else {
      foodColor = "#000000";
      var randomX = randomOffset(object.x, dpr, deviation);
      var randomY = randomOffset(object.y, dpr, deviation);
      var isMerge = false;
      //判断是否与以往材料相邻，相邻则合并
      for (
        var i = 0, foodListLength = foodList.length;
        i < foodListLength;
        i++
      ) {
        var food = foodList[i];
        if (food.number > 1 || food.color === "red") {
          continue;
        }
        if (
          calculateDistance(food, { x: randomX, y: randomY }) <
          (food.w + foodW) / 3
        ) {
          food.w *= 1.2;
          food.h *= 1.2;
          food.number++;
          isMerge = true;
          break;
        }
      }
      if (!isMerge) {
        foodList.push(
          new Food(
            randomX,
            randomY,
            foodW,
            foodH,
            foodRadius,
            Math.random() * 90,
            foodColor,
            1
          )
        );
      }
    }
  });
}

//生成随机火花
function generateRandomCoordinates(x, y, range, color) {
  var deviation = Math.random() * 36;

  var num = Math.random() * 2 + 5;

  for (let i = 1; i <= num; i++) {
    var angleInRadians = ((360 / num) * i * Math.PI) / 180 + deviation;
    var range = Math.random() * range * 0.4 + range * 0.8;
    var velocityX = Math.cos(angleInRadians) * range;
    var velocityY = Math.sin(angleInRadians) * range;
    let newX = x + velocityX;
    let newY = y + velocityY;
    sparkList.push(
      new Spark(
        newX,
        newY,
        angleInRadians,
        r / (Math.random() * 1.5 + 3),
        range,
        25,
        color
      )
    );
  }
}

//添加反弹子弹
function addBounce(bullet, object) {
  let minDistance = 10000000;
  let targetEnemy = undefined;
  for (
    let k = 0, enemyListLength = enemyList.length;
    k < enemyListLength;
    k++
  ) {
    let k_enemy = enemyList[k];

    if (object.type === "enemy") {
      //不计入当前enemy
      if (object.x === k_enemy.x && object.y === k_enemy.y) {
        continue;
      }
    }

    let currentDistance = calculateDistance(bullet, k_enemy);
    if (currentDistance < minDistance) {
      targetEnemy = k_enemy;
      minDistance = currentDistance;
    }
  }

  for (
    let k = 0, plantListLength = plantList.length;
    k < plantListLength;
    k++
  ) {
    let k_plant = plantList[k];

    if (object.type === "plant") {
      //不计入当前plant
      if (object.x === k_plant.x && object.y === k_plant.y) {
        continue;
      }
    }

    let currentDistance = calculateDistance(bullet, k_plant);
    if (currentDistance < minDistance) {
      targetEnemy = k_plant;
      minDistance = currentDistance;
    }
  }

  // if (minDistance <= bullet.range) {
  let newBullet = new Bullet(
    bullet.x,
    bullet.y,
    bullet.x,
    bullet.y,
    bullet.damage,
    0,
    0,
    undefined,
    bullet.distance,
    1000,
    1,
    bullet.position,
    bullet.bounce - 1,
    0,
    []
  );

  let templateX = newBullet.baseX - targetEnemy.x;
  let templateY = newBullet.baseY - targetEnemy.y;
  newBullet.radians = Math.atan2(templateY, templateX);
  newBullet.attackList.push(object.id);
  bulletList.push(newBullet);
  // }
}

//计算full
function buffCompute() {
  //计算自身增益
  if (speedBuffDuration <= 0) {
    speedBuff = 1;
  } else {
    speedBuffDuration--;
    $("#speedBuff").css({
      width: (100 * speedBuffDuration) / BASE_BUFF_DURATION + "%",
      backgroundColor: buffColor["speed"],
    });
    if (speedBuffDuration !== 0) {
      $("#speedBuffBox").show();
    } else {
      $("#speedBuffBox").hide();
    }
  }
  if (attackSpeedBuffDuration <= 0) {
    attackSpeedBuff = 1;
  } else {
    attackSpeedBuffDuration--;
    $("#attackSpeedBuff").css({
      width: (100 * attackSpeedBuffDuration) / BASE_BUFF_DURATION + "%",
      backgroundColor: buffColor["attack_speed"],
    });
    if (attackSpeedBuffDuration !== 0) {
      $("#attackSpeedBuffBox").show();
    } else {
      $("#attackSpeedBuffBox").hide();
    }
  }
  if (pickupRangeBuffDuration <= 0) {
    pickupRangeBuff = 1;
  } else {
    pickupRangeBuffDuration--;
    $("#pickupRangeBuff").css({
      width: (100 * pickupRangeBuffDuration) / BASE_BUFF_DURATION + "%",
      backgroundColor: buffColor["pickup_range"],
    });
    if (pickupRangeBuffDuration !== 0) {
      $("#pickupRangeBuffBox").show();
    } else {
      $("#pickupRangeBuffBox").hide();
    }
  }
}

//基本计算
function gameCompute() {
  if (gameState === 1) {
    absorbInterval--;
    trigonometricValue = getTrigonometricValue(); //闪烁幅度
    generatePlant();
    generateBuff();
    buffCompute();
    generateEnemy();
    initWeaponPosition();
    if (isDragging) {
      if (driftInterval === 0) {
        driftList.push(
          new Drift(
            myX + (Math.random() * r) / 1.5 - r / 3,
            myY + r / 2 + (Math.random() * r) / 1.5 - r / 3,
            (Math.random() * r) / 3 + r / 6,
            25,
            0.95,
            "#000000"
          )
        );
        //加速状态额外效果
        speedBuffDuration > 0 &&
          driftList.push(
            new Drift(
              myX + (Math.random() * r) / 1.5 - r / 3,
              myY + r / 2 + (Math.random() * r) / 1.5 - r / 3,
              (Math.random() * r) / 3 + r / 6,
              25,
              0.95,
              buffColor["speed"]
            )
          );
        driftInterval = 6;
      } else {
        driftInterval--;
      }
    }

    //计算我方下一画面的位置
    if (isDragging) {
      var angleInRadians = (angle * Math.PI) / 180;

      var velocityX = Math.cos(angleInRadians) * speed * speedBuff * dpr;
      var velocityY = Math.sin(angleInRadians) * speed * speedBuff * dpr;

      if (battlegroundX < canvasW_dpr / 2 - r && velocityX < 0) {
        myX += velocityX;

        //获取新坐标后，等量移动所有坐标
        myX -= velocityX;
        plantList.forEach(function (item) {
          item.x -= velocityX;
        });
        buffList.forEach(function (item) {
          item.x -= velocityX;
        });
        foodList.forEach(function (item) {
          item.x -= velocityX;
        });
        enemyList.forEach(function (item) {
          item.x -= velocityX;
        });
        bulletList.forEach(function (item) {
          item.x -= velocityX;
          item.fireX -= velocityX;
        });
        sparkList.forEach(function (item) {
          item.x -= velocityX;
        });
        driftList.forEach(function (item) {
          item.x -= velocityX;
        });
        boomSparkList.forEach(function (item) {
          item.x -= velocityX;
        });
        explosionList.forEach(function (item) {
          item.x -= velocityX;
        });
        deductionList.forEach(function (item) {
          item.x -= velocityX;
        });
        enemyBulletList.forEach(function (item) {
          item.x -= velocityX;
        });
        battlegroundX -= velocityX;
      }
      // if (battlegroundX > -(canvasW / 2) * 5 + r && velocityX > 0) {
      if (battlegroundX > -(canvasW_dpr / 2) * 3 + r && velocityX > 0) {
        myX += velocityX;

        //获取新坐标后，等量移动所有坐标
        myX -= velocityX;
        plantList.forEach(function (item) {
          item.x -= velocityX;
        });
        buffList.forEach(function (item) {
          item.x -= velocityX;
        });
        foodList.forEach(function (item) {
          item.x -= velocityX;
        });
        enemyList.forEach(function (item) {
          item.x -= velocityX;
        });
        bulletList.forEach(function (item) {
          item.x -= velocityX;
          item.fireX -= velocityX;
        });
        sparkList.forEach(function (item) {
          item.x -= velocityX;
        });
        driftList.forEach(function (item) {
          item.x -= velocityX;
        });
        boomSparkList.forEach(function (item) {
          item.x -= velocityX;
        });
        explosionList.forEach(function (item) {
          item.x -= velocityX;
        });
        deductionList.forEach(function (item) {
          item.x -= velocityX;
        });
        enemyBulletList.forEach(function (item) {
          item.x -= velocityX;
        });
        battlegroundX -= velocityX;
      }
      if (battlegroundY < canvasH_dpr / 2 - r && velocityY < 0) {
        myY += velocityY;

        //获取新坐标后，等量移动所有坐标
        myY -= velocityY;
        plantList.forEach(function (item) {
          item.y -= velocityY;
        });
        buffList.forEach(function (item) {
          item.y -= velocityY;
        });
        foodList.forEach(function (item) {
          item.y -= velocityY;
        });
        enemyList.forEach(function (item) {
          item.y -= velocityY;
        });
        bulletList.forEach(function (item) {
          item.y -= velocityY;
          item.fireY -= velocityY;
        });
        sparkList.forEach(function (item) {
          item.y -= velocityY;
        });
        driftList.forEach(function (item) {
          item.y -= velocityY;
        });
        boomSparkList.forEach(function (item) {
          item.y -= velocityY;
        });
        explosionList.forEach(function (item) {
          item.y -= velocityY;
        });
        deductionList.forEach(function (item) {
          item.y -= velocityY;
        });
        enemyBulletList.forEach(function (item) {
          item.y -= velocityY;
        });
        battlegroundY -= velocityY;
      }

      // if (battlegroundY > -(canvasH / 2) * 3 + r && velocityY > 0) {
      if (battlegroundY > -canvasH_dpr + r && velocityY > 0) {
        myY += velocityY;

        //获取新坐标后，等量移动所有坐标
        myY -= velocityY;
        plantList.forEach(function (item) {
          item.y -= velocityY;
        });
        buffList.forEach(function (item) {
          item.y -= velocityY;
        });
        foodList.forEach(function (item) {
          item.y -= velocityY;
        });
        enemyList.forEach(function (item) {
          item.y -= velocityY;
        });
        bulletList.forEach(function (item) {
          item.y -= velocityY;
          item.fireY -= velocityY;
        });
        sparkList.forEach(function (item) {
          item.y -= velocityY;
        });
        driftList.forEach(function (item) {
          item.y -= velocityY;
        });
        boomSparkList.forEach(function (item) {
          item.y -= velocityY;
        });
        explosionList.forEach(function (item) {
          item.y -= velocityY;
        });
        deductionList.forEach(function (item) {
          item.y -= velocityY;
        });
        enemyBulletList.forEach(function (item) {
          item.y -= velocityY;
        });
        battlegroundY -= velocityY;
      }
    }

    enemyKeepDistance();

    comeToMe();

    generateBullet();

    moveRok();

    moveEnemyBullet();

    //使用forEach，在遍历中增加数组长度不会影响遍历次数
    bulletList.forEach((bullet) => {
      if (bullet.currentPath > 0) {
        //判断敌方是否被子弹攻击
        for (
          var j = 0, enemyListLength = enemyList.length;
          j < enemyListLength;
          j++
        ) {
          var enemy = enemyList[j];

          //已经被该子弹攻击过的敌人不会再次受击
          if (bullet.attackList.includes(enemy.id)) {
            continue;
          }

          if (calculateDistance(bullet, enemy) <= r) {
            playStrikeAudio();
            //暴击率
            var n = Math.round(bullet.damage * damage);
            var color = "#ffffff";
            var size = 16;
            if (Math.random() < critChance) {
              n = n * 2;
              color = "#ff5000";
              // size = 17
            }
            deductionList.push(
              new Deduction(bullet.x, bullet.y, n, color, dpr * size, 50)
            );
            enemy.hp -= n;

            //吸血判断
            if (Math.random() < lifeSteal) {
              if (currentHP < baseHP) {
                deductionList.push(
                  new Deduction(myX, myY, "+1", "#08f000", dpr * 16, 50)
                );
                currentHP += 1;
                changeBlood();
              }
            }

            bullet.currentPath = 0;
            generateRandomCoordinates(bullet.x, bullet.y, dpr * 10, "red");
            // if (enemy.type === "tank") {
            generateRandomCoordinates(bullet.x, bullet.y, dpr * 6, "black");
            // }

            //击退效果
            if (enemy.hp > 0) {
              //如果是坦克在冲刺阶段，则没有击退效果
              if (!(enemy.type === "tank" && enemy.sprintDuration > 0)) {
                var velocityX =
                  Math.cos(bullet.radians) *
                  (knockBack > enemy.resistKnockBack
                    ? dpr * (knockBack - enemy.resistKnockBack)
                    : 0);
                var velocityY =
                  Math.sin(bullet.radians) *
                  (knockBack > enemy.resistKnockBack
                    ? dpr * (knockBack - enemy.resistKnockBack)
                    : 0);
                enemy.x -= velocityX;
                enemy.y -= velocityY;
              }
            } else {
              //设置死亡延迟时间以及方向
              corpseList.push(
                new Corpse(
                  enemy.x,
                  enemy.y,
                  enemy.r,
                  dpr * 3,
                  bullet.radians,
                  30
                )
              );
              var foodW = dpr * (Math.random() * 2 + 8);
              var foodH = dpr * (Math.random() * 2 + 8);
              var foodRadius = dpr * (Math.random() * 2 + 1);
              var foodColor = "#000000";
              if (Math.random() > 0.9) {
                foodColor = "red";
                foodW = foodW * 1.1;
                foodH = foodH * 1.1;
              }
              generateFood(enemy);

              //如果是trapEnemy，添加子弹
              if (enemy.type === "trap") {
                Array.from({ length: 10 }).forEach((_, index) => {
                  enemyBulletList.push(
                    new EnemyBullet(
                      "round",
                      enemy.x,
                      enemy.y,
                      r / 1.8,
                      Math.random() * 2 * Math.PI - Math.PI,
                      0.2 * dpr,
                      enemy.bulletDamage,
                      0
                    )
                  );
                });
              }
            }

            bullet.currentPath = 0;

            bullet.attackList.push(enemy.id);

            //判断反弹以及贯穿效果
            if (bullet.bounce > 0 && bullet.pierce === pierce) {
              //可以反弹
              addBounce(bullet, {
                id: enemy.id,
                type: "enemy",
                x: enemy.x,
                y: enemy.y,
              });
            }

            if (bullet.pierce > 0 && bullet.bounce === bounce) {
              //可以贯穿
              // addPierce(bullet)
              bullet.pierce--;
              bullet.baseX = bullet.x;
              bullet.baseY = bullet.y;
              bullet.currentPath = 1;
            }

            break;
          }
        }
      }

      if (bullet.currentPath > 0) {
        //判断植物是否被子弹攻击
        for (
          var j = 0, plantListLength = plantList.length;
          j < plantListLength;
          j++
        ) {
          var plant = plantList[j];

          //已经被该子弹攻击过的敌人不会再次受击
          if (bullet.attackList.includes(plant.id)) {
            continue;
          }

          if (calculateDistance(bullet, plant) <= r) {
            playStrikeAudio();
            //暴击率
            var n = Math.round(bullet.damage * damage);
            var color = "#ffffff";
            var size = 16;
            if (Math.random() < critChance) {
              n = n * 2;
              color = "#ff5000";
              // size = 17
            }
            deductionList.push(
              new Deduction(bullet.x, bullet.y, n, color, dpr * size, 50)
            );
            plant.hp -= n;
            bullet.currentPath = 0;
            generateRandomCoordinates(bullet.x, bullet.y, dpr * 10, "red");
            generateRandomCoordinates(bullet.x, bullet.y, dpr * 6, "black");

            //生成材料
            if (plant.hp <= 0) {
              var foodW = dpr * (Math.random() * 2 + 8);
              var foodH = dpr * (Math.random() * 2 + 8);
              var foodRadius = dpr * (Math.random() * 2 + 1);
              var foodColor = "#000000";
              generateFood({
                x: plant.x,
                y: plant.y,
                material: 5,
              });
            }
            bullet.currentPath = 0;

            bullet.attackList.push(plant.id);

            //判断反弹以及贯穿效果
            if (bullet.bounce > 0 && bullet.pierce === pierce) {
              //可以反弹
              if (bullet.bounce > 0) {
                //可以反弹
                addBounce(bullet, {
                  id: plant.id,
                  type: "plant",
                  x: plant.x,
                  y: plant.y,
                });
              }
            }

            if (bullet.pierce > 0 && bullet.bounce === bounce) {
              //可以贯穿
              // addPierce(bullet)
              bullet.pierce--;
              bullet.baseX = bullet.x;
              bullet.baseY = bullet.y;
              bullet.currentPath = 1;
            }

            break;
          }
        }
      }

      //判断子弹是否触碰到地图边界
      if (isOutMap(bullet)) {
        //消失效果
        explosionList.push(new Explosion(bullet.x, bullet.y, 20, bullet.r / 6));
        generateRandomCoordinates(bullet.x, bullet.y, dpr * 10, "ff5000");
        bullet.distance = 0;
      }

      //判断子弹是否超过最大距离
      if (
        calculateDistance(
          {
            x: bullet.baseX,
            y: bullet.baseY,
          },
          bullet
        ) >
        Math.round(bullet.range * attackRange) * 1.5
      ) {
        bullet.currentPath = 0;
      }
    }); //

    //移除失效子弹
    bulletList = bulletList.filter(
      (bullet) => bullet.currentPath > 0 && bullet.distance !== 0
    );

    //判断敌方是否被守卫攻击，子弹是否被守卫抵挡
    for (
      var i = 0, guardListLength = guardList.length;
      i < guardListLength;
      i++
    ) {
      var guard = guardList[i];

      //计算守卫新坐标
      var guardVelocityX = Math.cos(guard.radians) * guard.R;
      var guardVelocityY = Math.sin(guard.radians) * guard.R;
      guard.x = myX + guardVelocityX;
      guard.y = myY + guardVelocityY;

      //判断敌方是否被守卫攻击
      for (
        var j = 0, enemyListLength = enemyList.length;
        j < enemyListLength;
        j++
      ) {
        var enemy = enemyList[j];
        if (enemy.invincibleForGuard === 0) {
          if (calculateDistance(guard, enemy) <= enemy.r + guard.r) {
            var n = Math.round(guard.damage * damage);
            var color = "#ffffff";
            var size = 16;
            if (Math.random() < critChance) {
              n = n * 2;
              color = "#ff5000";
              // size = 17
            }
            deductionList.push(
              new Deduction(guard.x, guard.y, n, color, dpr * size, 50)
            );
            enemy.hp -= n;

            //进入无敌状态
            enemy.invincibleForGuard = 100;
            generateRandomCoordinates(guard.x, guard.y, dpr * 10, "red");

            //击退效果
            if (enemy.hp > 0) {
              if (!(enemy.type === "tank" && enemy.sprintDuration > 0)) {
                var velocityX =
                  Math.cos(guard.radians + Math.PI) *
                  (knockBack > enemy.resistKnockBack
                    ? dpr * (knockBack - enemy.resistKnockBack)
                    : 0);
                var velocityY =
                  Math.sin(guard.radians + Math.PI) *
                  (knockBack > enemy.resistKnockBack
                    ? dpr * (knockBack - enemy.resistKnockBack)
                    : 0);
                enemy.x -= velocityX;
                enemy.y -= velocityY;
              }
            } else {
              //设置死亡延迟时间以及方向
              corpseList.push(
                new Corpse(
                  enemy.x,
                  enemy.y,
                  enemy.r,
                  dpr * 3,
                  guard.radians + Math.PI,
                  30
                )
              );
              var foodW = dpr * (Math.random() * 2 + 8);
              var foodH = dpr * (Math.random() * 2 + 8);
              var foodRadius = dpr * (Math.random() * 2 + 1);
              var foodColor = "#000000";
              if (Math.random() > 0.8) {
                foodColor = "red";
                foodW = foodW * 1.1;
                foodH = foodH * 1.1;
              }
              generateFood(enemy);
            }
          }
        }
      }

      //判断子弹是否被守卫抵挡
      for (
        var j = 0, enemyBulletListLength = enemyBulletList.length;
        j < enemyBulletListLength;
        j++
      ) {
        var enemyBullet = enemyBulletList[j];
        if (calculateDistance(guard, enemyBullet) <= enemyBullet.r + guard.r) {
          enemyBullet.distance = 0;
          //添加爆炸效果
          explosionList.push(
            new Explosion(enemyBullet.x, enemyBullet.y, 20, enemyBullet.r / 6)
          );
          generateRandomCoordinates(
            enemyBullet.x,
            enemyBullet.y,
            dpr * 10,
            "red"
          );
        }
      }

      guard.radians += guard.speed;
    }

    //判断敌方是否被棍子攻击
    for (var i = 0, rokListLength = rokList.length; i < rokListLength; i++) {
      var rok = rokList[i];
      if (rok.duration <= 32 && rok.duration > 2) {
        var velocityX = Math.cos(rok.radians) * rok.l;
        var velocityY = Math.sin(rok.radians) * rok.l;
        var toX = rok.x + velocityX;
        var toY = rok.y + velocityY;
        for (
          var j = 0, enemyListLength = enemyList.length;
          j < enemyListLength;
          j++
        ) {
          var enemy = enemyList[j];
          if (enemy.invincible === 0) {
            //暂定首尾是两个判定点
            var head = {
              x: rok.headX,
              y: rok.headY,
            };
            var foot = {
              x: toX,
              y: toY,
            };
            var center = {
              x: (rok.headX + toX) / 2,
              y: (rok.headY + toY) / 2,
            };
            if (calculateDistance(head, enemy) < enemy.r * 2) {
              rokAttack(rok, enemy);
              continue;
            }
            if (calculateDistance(foot, enemy) < enemy.r * 2) {
              rokAttack(rok, enemy);
              continue;
            }
            if (calculateDistance(center, enemy) < enemy.r * 2) {
              rokAttack(rok, enemy);
              continue;
            }
          }
        }
      }
    }

    plantList = plantList.filter((item) => {
      return item.hp > 0;
    });

    enemyList = enemyList.filter((item) => {
      return item.hp > 0;
    });

    //判断是否被敌方攻击
    for (
      var i = 0, enemyListLength = enemyList.length;
      i < enemyListLength;
      i++
    ) {
      var enemy = enemyList[i];
      var my = {
        x: myX,
        y: myY,
      };
      var currentDistance = calculateDistance(my, enemy);
      if (currentDistance < r + enemy.r) {
        if (invincible === 0) {
          if (Math.random() > dodge) {
            currentHP -= enemy.damage;
            deductionList.push(
              new Deduction(myX, myY, -enemy.damage, "red", dpr * 16, 50)
            );
            generateRandomCoordinates(myX, myY, 10, "red");
            changeBlood();
          } else {
            deductionList.push(
              new Deduction(myX, myY, "DODGE", "#ffffff", dpr * 16, 30)
            );
          }
          invincible = baseInvincible;
          if (currentHP <= 0) {
            changeGameState(3);
          }
          break;
        }
      }
    }

    //判断我方是否被子弹攻击
    for (
      var i = 0, enemyBulletListLength = enemyBulletList.length;
      i < enemyBulletListLength;
      i++
    ) {
      var enemyBullet = enemyBulletList[i];
      var my = {
        x: myX,
        y: myY,
      };
      var currentDistance = calculateDistance(my, enemyBullet);
      if (currentDistance < r + enemyBullet.r) {
        //如果是导弹，添加效果
        if (enemyBullet.type === "missile") {
          explosionList.push(
            new Explosion(enemyBullet.x, enemyBullet.y, 20, enemyBullet.r / 6)
          );
        }
        generateRandomCoordinates(myX, myY, 10, "red");
        if (invincible === 0) {
          enemyBullet.distance = 0;
          if (Math.random() > dodge) {
            currentHP -= enemyBullet.damage;
            deductionList.push(
              new Deduction(myX, myY, -enemyBullet.damage, "red", dpr * 16, 50)
            );
            changeBlood();
          } else {
            deductionList.push(
              new Deduction(myX, myY, "DODGE", "#ffffff", dpr * 16, 30)
            );
          }
          invincible = baseInvincible;
          if (currentHP <= 0) {
            changeGameState(3);
          }
          break;
        }
      }
    }

    //子弹打到我方后消失
    enemyBulletList = enemyBulletList.filter((item) => item.distance !== 0);

    if (invincible > 0) {
      invincible--;
    }

    eatFood();

    pickUpFuff();

    determineUpgrade();

    drawFrame();

    var currentTime = new Date().getTime();

    //每隔一段时间渲染一次
    if (currentTime - updateFPSTime > 1000) {
      $("#fps").text("FPS: " + Math.round(1000 / (currentTime - lastTime)));
      updateFPSTime = currentTime;
    }
    lastTime = currentTime;
  }
}

//初始化武器位置
function initWeaponPosition() {
  for (var i = 0, rokListLength = rokList.length; i < rokListLength; i++) {
    var rok = rokList[i];
    if (rok.interval === 0) {
      if (rok.position === 0) {
        rok.x = myX;
        rok.y = myY + 1.5 * r;
      } else if (rok.position === 1) {
        rok.x = myX + 1.5 * r;
        rok.y = myY;
      } else if (rok.position === 2) {
        rok.x = myX;
        rok.y = myY - 1.5 * r;
      } else {
        rok.x = myX - 1.5 * r;
        rok.y = myY;
      }
    }
  }

  var gunPositionList = [];
  //这里先不考虑其他武器
  switch (gunList.length) {
    case 1:
      gunPositionList = [0];
      break;
    case 2:
      gunPositionList = [1, 3];
      break;
    case 3:
      gunPositionList = [0, 1, 3];
      break;
    case 4:
      gunPositionList = [0, 1, 2, 3];
      break;
  }

  for (var i = 0, gunListLength = gunList.length; i < gunListLength; i++) {
    var gun = gunList[i];
    gun.position = gunPositionList[i];
    if (gun.position === 0) {
      gun.baseX = myX;
      gun.baseY = myY + 1.5 * r;
    } else if (gun.position === 1) {
      gun.baseX = myX + 1.5 * r;
      gun.baseY = myY;
    } else if (gun.position === 2) {
      gun.baseX = myX;
      gun.baseY = myY - 1.5 * r;
    } else {
      gun.baseX = myX - 1.5 * r;
      gun.baseY = myY;
    }
  }
}

//根据位置获取x轴偏移
function getDeviationX(position) {
  if (position === 0) {
    return 0;
  } else if (position === 1) {
    return 1.5 * r;
  } else if (position === 2) {
    return 0;
  } else {
    return -1.5 * r;
  }
}

//根据位置获取y轴偏移
function getDeviationY(position) {
  if (position === 0) {
    return 1.5 * r;
  } else if (position === 1) {
    return 0;
  } else if (position === 2) {
    return -1.5 * r;
  } else {
    return 0;
  }
}

//判断是否超过地图边界
function isOutMap(object) {
  return (
    object.x <= battlegroundX + object.r ||
    object.x >= battlegroundX + battlegroundW - object.r ||
    object.y <= battlegroundY + object.r ||
    object.y >= battlegroundY + battlegroundH - object.r
  );
}

//敌方子弹移动
function moveEnemyBullet() {
  for (
    var i = 0, enemyBulletListLength = enemyBulletList.length;
    i < enemyBulletListLength;
    i++
  ) {
    var enemyBullet = enemyBulletList[i];
    var velocityX = Math.cos(enemyBullet.radians) * enemyBullet.distance;
    var velocityY = Math.sin(enemyBullet.radians) * enemyBullet.distance;
    enemyBullet.x += velocityX;
    enemyBullet.y += velocityY;

    //如果是导弹，持续时间结束后爆炸
    if (enemyBullet.type === "missile") {
      enemyBullet.duration--;
      if (enemyBullet.duration < 0) {
        //消失效果
        explosionList.push(
          new Explosion(enemyBullet.x, enemyBullet.y, 20, enemyBullet.r / 6)
        );
      }
    }

    if (isOutMap(enemyBullet)) {
      //消失效果
      explosionList.push(
        new Explosion(enemyBullet.x, enemyBullet.y, 20, enemyBullet.r / 6)
      );
      generateRandomCoordinates(enemyBullet.x, enemyBullet.y, dpr * 10, "red");
      enemyBullet.distance = 0;
    }
  }

  //敌方子弹碰撞边界或持续时间结束后消失
  enemyBulletList = enemyBulletList.filter(
    (item) => item.distance !== 0 && item.duration >= 0
  );
}

//棍子攻击
function rokAttack(rok, enemy) {
  var n = 8;
  var color = "#ffffff";
  var size = 16;
  if (Math.random() < 0.3) {
    n = n * 2;
    color = "#ff5000";
    // size = 17
  }
  deductionList.push(new Deduction(enemy.x, enemy.y, n, color, dpr * size, 50));
  enemy.hp -= n;
  //进入无敌状态
  enemy.invincible = 10;
  generateRandomCoordinates(enemy.x, enemy.y, dpr * 10, "#ff0000");
  generateRandomCoordinates(enemy.x, enemy.y, dpr * 6, "#08f000");
  //击退效果
  if (enemy.hp > 0) {
    var velocityX = Math.cos(rok.radians + Math.PI) * 4;
    var velocityY = Math.sin(rok.radians + Math.PI) * 4;
    enemy.x -= velocityX;
    enemy.y -= velocityY;
  } else {
    //设置死亡延迟时间以及方向
    corpseList.push(
      new Corpse(enemy.x, enemy.y, enemy.r, dpr * 3, rok.radians + Math.PI, 30)
    );
    var foodW = dpr * (Math.random() * 2 + 8);
    var foodH = dpr * (Math.random() * 2 + 8);
    var foodRadius = dpr * (Math.random() * 2 + 1);
    var foodColor = "#000000";
    if (Math.random() > 0.8) {
      foodColor = "red";
      foodW = foodW * 1.1;
      foodH = foodH * 1.1;
    }
    generateFood(enemy);
  }
}

//棍子移动
function moveRok() {
  for (var i = 0, rokListLength = rokList.length; i < rokListLength; i++) {
    var rok = rokList[i];
    var minDistance = 0;
    var targetEnemy = undefined;
    if (rok.interval === 0) {
      //判断是否在进行攻击流程
      if (rok.duration === 0) {
        for (
          var j = 0, enemyListLength = enemyList.length;
          j < enemyListLength;
          j++
        ) {
          var enemy = enemyList[j];
          var currentDistance = calculateDistance(rok, enemy);

          if (j === 0) {
            targetEnemy = enemy;
            minDistance = currentDistance;
            continue;
          }
          if (currentDistance < minDistance) {
            targetEnemy = enemy;
            minDistance = currentDistance;
          }
        }

        if (minDistance <= rok.range) {
          var templateX = targetEnemy.x - rok.x;
          var templateY = targetEnemy.y - rok.y;
          rok.radians = Math.atan2(templateY, templateX);
          //若达到攻击范围，计算初始攻击角度
          if (minDistance <= rok.actionRange) {
            rok.duration = 40;
            // 计算旋转圆心以及首位坐标
            templateX = targetEnemy.x - (myX + getDeviationX(rok.position));
            templateY = targetEnemy.y - (myY + getDeviationY(rok.position));
            var tempRadians = Math.atan2(templateY, templateX);
            rok.centerX =
              myX + getDeviationX(rok.position) + Math.cos(tempRadians);
            rok.centerY =
              myY + getDeviationY(rok.position) + Math.sin(tempRadians);
            if (targetEnemy.x < myX) {
              rok.direction = "left";
              rok.headX =
                myX +
                getDeviationX(rok.position) +
                Math.cos(tempRadians + 1) * 40 * dpr;
              rok.headY =
                myY +
                getDeviationY(rok.position) +
                Math.sin(tempRadians + 1) * 40 * dpr;
              rok.tempRadians = tempRadians + Math.PI;
            } else {
              rok.direction = "right";
              rok.headX =
                myX +
                getDeviationX(rok.position) +
                Math.cos(tempRadians - 1) * 40 * dpr;
              rok.headY =
                myY +
                getDeviationY(rok.position) +
                Math.sin(tempRadians - 1) * 40 * dpr;
              rok.tempRadians = tempRadians - Math.PI;
            }
          }
        }
      }
      rok.interval = 40;
    } else {
      //根据我方行走方向修改rok方向
      // rok.radians = Math.PI / 4 < angle * Math.PI / 180 <3 * Math.PI / 4?rok.radians:-rok.radians;
      // rok.radians = 0
      if (rok.interval > 0) {
        rok.interval--;
      }
    }
  }
}

//拾取材料
function eatFood() {
  for (var i = 0, foodListLength = foodList.length; i < foodListLength; i++) {
    var food = foodList[i];

    var my = {
      x: myX,
      y: myY,
    };
    var currentDistance = calculateDistance(my, food);
    //判断是否被吃
    if (currentDistance < r) {
      food.isEat = true;
      score += food.number;
      if (food.number > 1) {
        deductionList.push(
          new Deduction(
            food.x,
            food.y,
            "X" + food.number,
            "#ffffff",
            dpr * 16,
            50
          )
        );
      }
      changeExp();
      playEatAudio();
      generateRandomCoordinates(myX, myY, dpr * 10, "#08f000");
      if (food.color === "red") {
        if (currentHP < baseHP) {
          if (baseHP - currentHP <= 2) {
            deductionList.push(
              new Deduction(
                food.x,
                food.y,
                "+" + (baseHP - currentHP),
                "#08f000",
                dpr * 16,
                50
              )
            );
            currentHP = baseHP;
          } else {
            deductionList.push(
              new Deduction(food.x, food.y, "+2", "#08f000", dpr * 16, 50)
            );
            currentHP += 2;
          }
        }

        changeBlood();
      }
      continue;
    }
    //食物向玩家移动
    if (
      currentDistance <
      (absorbInterval > 0
        ? 9999 * dpr * pickupRange
        : 50 * dpr * pickupRange * pickupRangeBuff)
    ) {
      var templateX = myX - food.x;
      var templateY = myY - food.y;
      // 计算角度
      var angleInRadians = Math.atan2(templateY, templateX);
      var velocityX =
        absorbInterval > 0
          ? dpr * Math.cos(angleInRadians) * 4
          : dpr * Math.cos(angleInRadians) * 2;
      var velocityY =
        absorbInterval > 0
          ? dpr * Math.sin(angleInRadians) * 4
          : dpr * Math.sin(angleInRadians) * 2;
      food.x += velocityX;
      food.y += velocityY;
    }
  }
  foodList = foodList.filter((item) => {
    return !item.isEat;
  });
}

//拾取buff
function pickUpFuff() {
  for (var i = 0, buffListLength = buffList.length; i < buffListLength; i++) {
    var buff = buffList[i];

    var my = {
      x: myX,
      y: myY,
    };
    var currentDistance = calculateDistance(my, buff);
    //判断是否被吃
    if (currentDistance < r) {
      buff.isEat = true;
      //拾取后的逻辑
      playEatAudio();
      generateRandomCoordinates(myX, myY, dpr * 12, buff.color);
      switch (buff.type) {
        case "speed":
          speedBuff = 2;
          speedBuffDuration = BASE_BUFF_DURATION;
          break;
        case "attack_speed":
          attackSpeedBuff = 2;
          attackSpeedBuffDuration = BASE_BUFF_DURATION;
          break;
        case "pickup_range":
          pickupRangeBuff = 2;
          pickupRangeBuffDuration = BASE_BUFF_DURATION;
          break;
      }

      continue;
    }
    //食物向玩家移动
    if (currentDistance < 50 * dpr * pickupRange * 0.8 * pickupRangeBuff) {
      var templateX = myX - buff.x;
      var templateY = myY - buff.y;
      // 计算角度
      var angleInRadians = Math.atan2(templateY, templateX);
      var velocityX =
        absorbInterval > 0
          ? dpr * Math.cos(angleInRadians) * 4
          : dpr * Math.cos(angleInRadians) * 2;
      var velocityY =
        absorbInterval > 0
          ? dpr * Math.sin(angleInRadians) * 4
          : dpr * Math.sin(angleInRadians) * 2;
      buff.x += velocityX;
      buff.y += velocityY;
    }
  }
  buffList = buffList.filter((item) => {
    return !item.isEat;
  });
}

//枪生成子弹
function generateBullet() {
  for (var i = 0, gunListLength = gunList.length; i < gunListLength; i++) {
    var gun = gunList[i];
    var minDistance = 0;
    var targetEnemy = undefined;
    if (gun.currentInterval === 0) {
      //冷却结束，根据敌人判断是否发射下一个子弹
      for (
        var j = 0, enemyListLength = enemyList.length;
        j < enemyListLength;
        j++
      ) {
        var enemy = enemyList[j];
        // var my = {
        //     x: myX,
        //     y: myY,
        // }
        var my = {
          //用枪的位置判断，防止所有枪总是攻击同一个敌人
          x: gun.baseX,
          y: gun.baseY,
        };
        var currentDistance = calculateDistance(my, enemy);
        if (j === 0) {
          targetEnemy = enemy;
          minDistance = currentDistance;
          continue;
        }
        if (currentDistance < minDistance) {
          targetEnemy = enemy;
          minDistance = currentDistance;
        }
      }

      //判断是否攻击植物
      for (
        var j = 0, plantListLength = plantList.length;
        j < plantListLength;
        j++
      ) {
        var plant = plantList[j];
        var my = {
          x: myX,
          y: myY,
        };
        var currentDistance = calculateDistance(my, plant);
        if (currentDistance < minDistance) {
          targetEnemy = plant;
          minDistance = currentDistance;
        }
      }

      if (minDistance <= Math.round(gun.range * attackRange)) {
        var newBullet = new Bullet(
          0,
          0,
          gun.baseX,
          gun.baseY,
          gun.damage,
          0,
          0,
          undefined,
          Math.round(gun.distance * attackSpeed * 1.5),
          gun.range,
          1,
          gun.position,
          bounce,
          pierce,
          []
        );

        var templateX = newBullet.baseX - targetEnemy.x;
        var templateY = newBullet.baseY - targetEnemy.y;
        newBullet.radians = Math.atan2(templateY, templateX);
        newBullet.x =
          newBullet.baseX - Math.cos(newBullet.radians) * newBullet.distance;
        newBullet.y =
          newBullet.baseY - Math.sin(newBullet.radians) * newBullet.distance;
        newBullet.fireX =
          newBullet.baseX - Math.cos(newBullet.radians) * (r / 2.5 + r / 1.5);
        newBullet.fireY =
          newBullet.baseY - Math.sin(newBullet.radians) * (r / 2.5 + r / 1.5);
        bulletList.push(newBullet);
      }
      //重置冷却时间
      gun.currentInterval = Math.round(
        gun.baseInterval * Math.exp(1 - attackSpeed * attackSpeedBuff)
      );
    } else {
      gun.currentInterval--;
    }
  }
}

//敌方向我方移动
function comeToMe() {
  for (
    var i = 0, enemyListLength = enemyList.length;
    i < enemyListLength;
    i++
  ) {
    var enemy = enemyList[i];
    var templateX = myX - enemy.x;
    var templateY = myY - enemy.y;
    // 计算角度
    var enemyAngleInRadians = Math.atan2(templateY, templateX);
    enemy.radians = enemyAngleInRadians;
    var enemyVelocityX = Math.cos(enemyAngleInRadians) * enemy.speed;
    var enemyVelocityY = Math.sin(enemyAngleInRadians) * enemy.speed;

    var distanceFromEnemyToMe = calculateDistance({ x: myX, y: myY }, enemy);

    //若是弹幕怪，则判断生成弹幕，并且在一定范围内后不再靠近
    if (enemy.type === "common") {
      enemy.x += enemyVelocityX;
      enemy.y += enemyVelocityY;
    } else if (enemy.type === "bubble") {
      if (enemy.attackInterval === 0) {
        //生成弹幕
        enemyBulletList.push(
          new EnemyBullet(
            "round",
            enemy.x,
            enemy.y,
            r / 1.5,
            enemyAngleInRadians,
            0.8 * dpr,
            enemy.bulletDamage,
            0
          )
        );
        enemy.attackInterval = 700;
      } else {
        enemy.attackInterval--;
      }

      if (distanceFromEnemyToMe < Math.round(dpr * 180)) {
        enemy.x -= enemyVelocityX;
        enemy.y -= enemyVelocityY;
        //将敌人限制战场内
        enemy.x =
          enemy.x < battlegroundX + enemy.r ? battlegroundX + enemy.r : enemy.x;
        enemy.x =
          enemy.x > battlegroundX + battlegroundW - enemy.r
            ? battlegroundX + battlegroundW - enemy.r
            : enemy.x;
        enemy.y =
          enemy.y < battlegroundY + enemy.r ? battlegroundY + enemy.r : enemy.y;
        enemy.y =
          enemy.y > battlegroundY + battlegroundH - enemy.r
            ? battlegroundY + battlegroundH - enemy.r
            : enemy.y;
        enemy.moveType = "leave";
      } else if (distanceFromEnemyToMe === Math.round(dpr * 180)) {
        enemy.moveType = "stay";
      } else {
        enemy.x += enemyVelocityX;
        enemy.y += enemyVelocityY;
        enemy.moveType = "come";
      }
    } else if (enemy.type === "machine") {
      if (enemy.attackInterval === 0) {
        //生成弹幕
        Array.from({ length: 3 }).forEach((_, index) => {
          enemyBulletList.push(
            new EnemyBullet(
              "round",
              enemy.x,
              enemy.y,
              r / 1.8,
              enemyAngleInRadians + Math.random() * 0.5 - 0.25,
              dpr * (Math.random() * 0.2 + 0.5),
              enemy.bulletDamage,
              0
            )
          );
        });
        enemy.attackInterval = 500;
      } else {
        enemy.attackInterval--;
      }

      if (distanceFromEnemyToMe < Math.round(dpr * 240)) {
        enemy.x -= enemyVelocityX;
        enemy.y -= enemyVelocityY;
        //将敌人限制战场内
        enemy.x =
          enemy.x < battlegroundX + enemy.r ? battlegroundX + enemy.r : enemy.x;
        enemy.x =
          enemy.x > battlegroundX + battlegroundW - enemy.r
            ? battlegroundX + battlegroundW - enemy.r
            : enemy.x;
        enemy.y =
          enemy.y < battlegroundY + enemy.r ? battlegroundY + enemy.r : enemy.y;
        enemy.y =
          enemy.y > battlegroundY + battlegroundH - enemy.r
            ? battlegroundY + battlegroundH - enemy.r
            : enemy.y;
        enemy.moveType = "leave";
      } else if (distanceFromEnemyToMe === Math.round(dpr * 240)) {
        enemy.moveType = "stay";
      } else {
        enemy.x += enemyVelocityX;
        enemy.y += enemyVelocityY;
        enemy.moveType = "come";
      }
    } else if (enemy.type === "charge") {
      //判断持续攻击是否结束
      if (enemy.attackRestInterval === 0) {
        if (enemy.attackInterval === 0) {
          //生成弹幕
          if (enemy.bulletNumber > 0) {
            enemyBulletList.push(
              new EnemyBullet(
                "triangle",
                enemy.x,
                enemy.y,
                r / 1.8,
                enemyAngleInRadians + Math.random() * 0.4 - 0.2,
                2.4 * dpr,
                enemy.bulletDamage,
                0
              )
            );
            enemy.attackInterval = 30;
            enemy.bulletNumber--;
          } else {
            //子弹射击完停止持续攻击
            enemy.bulletNumber = 5;
            enemy.attackRestInterval = 300;
          }
        } else {
          enemy.attackInterval--;
        }
      } else {
        enemy.attackRestInterval--;
      }

      //如果正在持续攻击，则控制范围为150，否则为300（远离玩家）
      var chargeRange =
        enemy.attackRestInterval === 0
          ? Math.round(dpr * 150)
          : Math.round(dpr * 250);

      if (distanceFromEnemyToMe < chargeRange) {
        enemy.x -= enemyVelocityX;
        enemy.y -= enemyVelocityY;
        //将敌人限制战场内
        enemy.x =
          enemy.x < battlegroundX + enemy.r ? battlegroundX + enemy.r : enemy.x;
        enemy.x =
          enemy.x > battlegroundX + battlegroundW - enemy.r
            ? battlegroundX + battlegroundW - enemy.r
            : enemy.x;
        enemy.y =
          enemy.y < battlegroundY + enemy.r ? battlegroundY + enemy.r : enemy.y;
        enemy.y =
          enemy.y > battlegroundY + battlegroundH - enemy.r
            ? battlegroundY + battlegroundH - enemy.r
            : enemy.y;
        enemy.moveType = "leave";
      } else if (distanceFromEnemyToMe === chargeRange) {
        enemy.moveType = "stay";
      } else {
        enemy.x += enemyVelocityX;
        enemy.y += enemyVelocityY;
        enemy.moveType = "come";
      }
    } else if (enemy.type === "tank") {
      // enemy.x += enemyVelocityX;
      // enemy.y += enemyVelocityY;

      //冲刺逻辑
      if (enemy.sprintInterval === 0) {
        if (enemy.sprintDuration === 0) {
          //冲刺初始化
          if (distanceFromEnemyToMe < Math.round(dpr * 200)) {
            enemy.sprintDuration = 130;
            enemy.sprintRadians = enemyAngleInRadians;
          }
        } else {
          if (enemy.sprintDuration > 100) {
            //准备过程
            enemy.sprintDuration--;
          } else {
            //冲刺过程
            let enemyVelocityX =
              Math.cos(enemy.sprintRadians) * enemy.speed * 5;
            let enemyVelocityY =
              Math.sin(enemy.sprintRadians) * enemy.speed * 5;
            //当超过地图边界时提前结束
            if (isOutMap(enemy)) {
              enemy.sprintDuration = 0;
              enemy.sprintInterval = 200;
            } else {
              enemy.x += enemyVelocityX;
              enemy.y += enemyVelocityY;
              enemy.sprintDuration--;
              if (enemy.sprintDuration === 0) {
                //冲刺结束进入冷却
                enemy.sprintInterval = 250;
              }
            }
          }
        }
      } else {
        enemy.sprintInterval--;
      }

      if (enemy.sprintDuration === 0) {
        //未冲刺时正常移动
        enemy.x += enemyVelocityX;
        enemy.y += enemyVelocityY;
      }
    } else if (enemy.type === "boom") {
      if (distanceFromEnemyToMe < Math.round(dpr * 50)) {
        enemy.x -= enemyVelocityX;
        enemy.y -= enemyVelocityY;
        enemy.x =
          enemy.x < battlegroundX + enemy.r ? battlegroundX + enemy.r : enemy.x;
        enemy.x =
          enemy.x > battlegroundX + battlegroundW - enemy.r
            ? battlegroundX + battlegroundW - enemy.r
            : enemy.x;
        enemy.y =
          enemy.y < battlegroundY + enemy.r ? battlegroundY + enemy.r : enemy.y;
        enemy.y =
          enemy.y > battlegroundY + battlegroundH - enemy.r
            ? battlegroundY + battlegroundH - enemy.r
            : enemy.y;
        enemy.moveType = "leave";
      } else if (distanceFromEnemyToMe === Math.round(dpr * 50)) {
        enemy.moveType = "stay";
      } else {
        //在攻击时停止
        if (
          enemy.boomInterval < 30 &&
          distanceFromEnemyToMe < Math.round(dpr * 180)
        ) {
          enemy.moveType = "stay";
        } else {
          enemy.x += enemyVelocityX;
          enemy.y += enemyVelocityY;
          enemy.moveType = "come";
        }
      }
      if (enemy.boomInterval === 0) {
        if (distanceFromEnemyToMe < Math.round(dpr * 180)) {
          //添加爆炸元素
          Array.from({ length: 30 }).forEach((_, index) => {
            var angleInRadians = Math.random() * 2 * Math.PI; //获取任意弧度
            var velocityX =
              Math.cos(angleInRadians) * Math.random() * Math.round(dpr * 100);
            var velocityY =
              Math.sin(angleInRadians) * Math.random() * Math.round(dpr * 100);
            let newX = enemy.x + velocityX;
            let newY = enemy.y + velocityY;
            boomSparkList.push(
              new BoomSpark(
                newX,
                newY,
                Math.random() * dpr * 5 + dpr * 2,
                25,
                "#ff0000"
              )
            );
          });
        }

        //直接判断是否波及到我方
        if (distanceFromEnemyToMe < Math.round(dpr * 100)) {
          if (invincible === 0) {
            if (Math.random() > dodge) {
              currentHP -= enemy.boomDamage;
              deductionList.push(
                new Deduction(myX, myY, -enemy.boomDamage, "red", dpr * 16, 50)
              );
              generateRandomCoordinates(myX, myY, 10, "red");
              changeBlood();
            } else {
              deductionList.push(
                new Deduction(myX, myY, "DODGE", "#ffffff", dpr * 16, 30)
              );
            }
            invincible = baseInvincible;
            if (currentHP <= 0) {
              changeGameState(3);
            }
            break;
          }
        }

        enemy.boomInterval = 200;
      } else {
        enemy.boomInterval--;
      }
    } else if (enemy.type === "trap") {
      enemy.x += enemyVelocityX;
      enemy.y += enemyVelocityY;
    } else if (enemy.type === "missile") {
      if (enemy.attackInterval === 0) {
        if (distanceFromEnemyToMe < Math.round(dpr * 400)) {
          //生成弹幕
          enemyBulletList.push(
            new EnemyBullet(
              "missile",
              enemy.x,
              enemy.y,
              r / 1.5,
              enemyAngleInRadians,
              0.8 * dpr,
              enemy.bulletDamage,
              1000
            )
          );
          enemy.attackInterval = 800;
        }
      } else {
        enemy.attackInterval--;
      }

      if (distanceFromEnemyToMe < Math.round(dpr * 350)) {
        enemy.x -= enemyVelocityX;
        enemy.y -= enemyVelocityY;
        //将敌人限制战场内
        enemy.x =
          enemy.x < battlegroundX + enemy.r ? battlegroundX + enemy.r : enemy.x;
        enemy.x =
          enemy.x > battlegroundX + battlegroundW - enemy.r
            ? battlegroundX + battlegroundW - enemy.r
            : enemy.x;
        enemy.y =
          enemy.y < battlegroundY + enemy.r ? battlegroundY + enemy.r : enemy.y;
        enemy.y =
          enemy.y > battlegroundY + battlegroundH - enemy.r
            ? battlegroundY + battlegroundH - enemy.r
            : enemy.y;
        enemy.moveType = "leave";
      } else if (distanceFromEnemyToMe === Math.round(dpr * 350)) {
        enemy.moveType = "stay";
      } else {
        enemy.x += enemyVelocityX;
        enemy.y += enemyVelocityY;
        enemy.moveType = "come";
      }
    }
  }
}

//调整敌人之间的距离（调整坐标，保证敌人不重合）
function enemyKeepDistance() {
  //遍历敌人
  for (
    var i = 0, enemyListLength = enemyList.length;
    i < enemyListLength;
    i++
  ) {
    var targetEnemy = enemyList[i];
    for (var j = i + 1; j < enemyListLength - i - 1; j++) {
      var nextEnemy = enemyList[j];
      if (calculateDistance(targetEnemy, nextEnemy) < 1.3 * r) {
        var templateX = targetEnemy.x - nextEnemy.x;
        var templateY = targetEnemy.y - nextEnemy.y;
        // 计算角度
        var enemyAngleInRadians = Math.atan2(templateY, templateX);
        var enemyVelocityX = Math.cos(enemyAngleInRadians) * enemySpeed;
        var enemyVelocityY = Math.sin(enemyAngleInRadians) * enemySpeed;
        nextEnemy.x -= enemyVelocityX;
        nextEnemy.y -= enemyVelocityY;
      }
    }
  }
}

//初始化
function init() {
  $(".action-box").show();
  $(".action").show();

  ctx.clearRect(0, 0, canvas.width, canvas.height);

  screenW = window.innerWidth;
  screenH = window.innerHeight;
  canvasW = screenW > 750 ? 750 : screenW;
  canvasH = screenH;
  baseW = $("body").width();

  canvas.style.width = `${canvasW}px`;
  canvas.style.height = `${canvasH}px`;

  canvas.width = canvasW * dpr;
  canvas.height = canvasH * dpr;

  // 6. 设置 Canvas 背景色
  canvas.style.backgroundColor = "#000000";

  // 7. 获取 2D 上下文，并缩放以匹配 DPR
  ctx = canvas.getContext("2d");
  ctx.scale(dpr, dpr); // 关键：确保绘图坐标仍按 CSS 像素计算

  // 8. 游戏逻辑变量初始化（保持不变）
  battlegroundX = (-canvasW / 2) * dpr;
  battlegroundY = (-canvasH / 4) * dpr;
  battlegroundW = canvasW * 2 * dpr;
  battlegroundH = canvasH * 1.5 * dpr;
  myX = (canvasW / 2) * dpr;
  myY = (canvasH / 2) * dpr;

  canvasW_dpr = canvasW * dpr;
  canvasH_dpr = canvasH * dpr;

  foodList = [];
  enemyList = [];
  score = 0;
  grade = 0;
  damage = 1;
  speed = 1;
  attackSpeed = 1; // 攻速
  lifeSteal = 0.05; // 吸血
  critChance = 0.05; // 暴击
  dodge = 0; // 闪避
  knockBack = 5; // 击退
  attackRange = 1; // 攻击范围
  pickupRange = 1; // 拾取范围
  bounce = 0; // 反弹
  pierce = 0; // 贯穿

  //buff
  speedBuff = 1;
  attackSpeedBuff = 1;
  pickupRangeBuff = 1;

  speedBuffDuration = 0;
  attackSpeedBuffDuration = 0;
  pickupRangeBuffDuration = 0;

  gunNumber = 1;
  guardNumber = 0;
  enemySpeed = 0.5;
  angle = 0; // 设定角度
  gunList = [];
  bulletList = [];
  guardList = [];
  rokList = [];
  sparkList = [];
  driftList = [];
  boomSparkList = [];
  explosionList = [];
  deductionList = [];
  corpseList = [];
  enemyBulletList = [];
  plantList = [];
  buffList = [];
  plantInterval = 60;
  shape = 0;
  baseHP = 15;
  currentHP = 15;
  invincible = 0;
  baseInvincible = 30;
  myDirection = "right";
  drawInterval = 15;
  commonNumber = 0;
  bubbleNumber = 0;
  machineNumber = 0;
  chargeNumber = 0;
  tankNumber = 0;
  boomNumber = 0;
  trapNumber = 0;
  missileNumber = 0;

  $("#score").text(score);
  changeBlood();
  changeExp();

  for (var i = 0; i < gunNumber; i++) {
    gunList.push(new Gun(0, 0, 6, dpr * 5, 60, 0, dpr * 180, 0));
  }

  var radians = (2 * Math.PI) / guardNumber;
  for (var i = 0; i < guardNumber; i++) {
    guardList.push(
      new Guard(0, 0, dpr * 60, r / 2, 0.02, radians * i, "#000000", 2)
    );
  }

  // rokList.push(new Rok(0, 0, 0, 0, 0, 0, dpr * 40, Math.PI / 8, dpr * 200, dpr * 80, 0, 0, undefined, 0))
  // rokList.push(new Rok(0, 0, 0, 0, 0, 0, dpr * 40, Math.PI / 8, dpr * 200, dpr * 80, 0, 0, undefined, 3))

  if (begin) {
    clearInterval(begin);
  }

  initEnemyNumber();

  // 不停绘制图像
  begin = setInterval(gameCompute, drawInterval);
}

//判断是否有游戏记录
if (localStorage.getItem("gameStateInfo")) {
  begin = setInterval(gameCompute, drawInterval);
  var gameStateInfo = JSON.parse(localStorage.getItem("gameStateInfo"));

  var rawFoodList = gameStateInfo.foodList;
  foodList = rawFoodList.map(
    (data) =>
      new Food(
        data.x,
        data.y,
        data.w,
        data.h,
        data.radius,
        data.radians,
        data.color,
        data.number
      )
  );
  enemyList = gameStateInfo.enemyList;
  var rawEnemyList = gameStateInfo.enemyList;
  enemyList = rawEnemyList.map((data) => {
    switch (data.type) {
      case "common":
        return new Enemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack
        );
        break;
      case "bubble":
        return new BubbleEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.attackInterval,
          data.bulletDamage
        );
        break;
      case "machine":
        return new MachineEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.attackInterval,
          data.bulletDamage
        );
        break;
      case "charge":
        return new ChargeEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.attackInterval,
          data.bulletDamage,
          data.bulletNumber,
          data.attackRestInterval
        );
        break;
      case "tank":
        return new TankEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.sprintRadians,
          data.sprintInterval,
          data.sprintDuration
        );
        break;
      case "boom":
        return new BoomEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.boomInterval,
          data.boomDamage
        );
        break;
      case "trap":
        return new TrapEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.bulletDamage
        );
        break;
      case "missile":
        return new MissileEnemy(
          data.id,
          data.type,
          data.x,
          data.y,
          data.r,
          data.hp,
          data.material,
          data.speed,
          data.damage,
          data.shape,
          data.color,
          data.invincible,
          data.invincibleForGuard,
          data.markDeath,
          data.moveType,
          data.resistKnockBack,
          data.bulletDamage
        );
        break;
    }
  });

  score = gameStateInfo.score;
  grade = gameStateInfo.grade;
  damage = gameStateInfo.damage;
  speed = gameStateInfo.speed;
  attackSpeed = gameStateInfo.attackSpeed;
  lifeSteal = gameStateInfo.lifeSteal;
  critChance = gameStateInfo.critChance;
  dodge = gameStateInfo.dodge;
  knockBack = gameStateInfo.knockBack;
  attackRange = gameStateInfo.attackRange;
  pickupRange = gameStateInfo.pickupRange;
  bounce = gameStateInfo.bounce;
  pierce = gameStateInfo.pierce;
  gunNumber = gameStateInfo.gunNumber;
  guardNumber = gameStateInfo.guardNumber;
  enemySpeed = gameStateInfo.enemySpeed;
  angle = gameStateInfo.angle;
  battlegroundX = gameStateInfo.battlegroundX;
  battlegroundY = gameStateInfo.battlegroundY;
  myX = gameStateInfo.myX;
  myY = gameStateInfo.myY;

  var rawGunList = gameStateInfo.gunList;
  gunList = rawGunList.map(
    (data) =>
      new Gun(
        data.baseX,
        data.baseY,
        data.damage,
        data.distance,
        data.baseInterval,
        data.currentInterval,
        data.range,
        data.position
      )
  );

  var rawBulletList = gameStateInfo.bulletList;
  bulletList = rawBulletList.map(
    (data) =>
      new Bullet(
        data.x,
        data.y,
        data.baseX,
        data.baseY,
        data.damage,
        data.fireX,
        data.fireY,
        data.radians,
        data.distance,
        data.range,
        data.currentPath,
        data.position,
        data.bounce,
        data.pierce,
        data.attackList
      )
  );

  var rawGuardList = gameStateInfo.guardList;
  guardList = rawGuardList.map(
    (data) =>
      new Guard(
        data.x,
        data.y,
        data.R,
        data.r,
        data.speed,
        data.radians,
        data.color,
        data.damage
      )
  );

  var rawRokList = gameStateInfo.rokList;
  rokList = rawRokList.map(
    (data) =>
      new Rok(
        data.x,
        data.y,
        data.centerX,
        data.centerY,
        data.headX,
        data.headY,
        data.l,
        data.radians,
        data.range,
        data.actionRange,
        data.duration,
        data.interval,
        data.direction,
        data.position
      )
  );

  var rawSparkList = gameStateInfo.sparkList;
  sparkList = rawSparkList.map(
    (data) =>
      new Spark(
        data.x,
        data.y,
        data.radians,
        data.r,
        data.range,
        data.duration,
        data.color
      )
  );

  var rawDriftList = gameStateInfo.driftList;
  driftList = rawDriftList.map(
    (data) =>
      new Drift(data.x, data.y, data.r, data.duration, data.decay, data.color)
  );

  var rawBoomSparkList = gameStateInfo.boomSparkList;
  boomSparkList = rawBoomSparkList.map(
    (data) => new BoomSpark(data.x, data.y, data.r, data.duration, data.color)
  );

  var rawExplosionList = gameStateInfo.explosionList;
  explosionList = rawExplosionList.map(
    (data) => new Explosion(data.x, data.y, data.duration, data.growthSpeed)
  );

  var rawDeductionList = gameStateInfo.deductionList;
  deductionList = rawDeductionList.map(
    (data) =>
      new Deduction(
        data.x,
        data.y,
        data.n,
        data.color,
        data.size,
        data.duration
      )
  );

  var rawCorpseList = gameStateInfo.corpseList;
  corpseList = rawCorpseList.map(
    (data) =>
      new Corpse(
        data.x,
        data.y,
        data.r,
        data.distance,
        data.radians,
        data.delay
      )
  );

  var rawEnemyBulletList = gameStateInfo.enemyBulletList;
  enemyBulletList = rawEnemyBulletList.map(
    (data) =>
      new EnemyBullet(
        data.type,
        data.x,
        data.y,
        data.r,
        data.radians,
        data.distance,
        data.damage,
        data.duration
      )
  );

  var rawPlantList = gameStateInfo.plantList;
  plantList = rawPlantList.map(
    (data) => new Plant(data.id, data.x, data.y, data.hp)
  );

  var rawBuffList = gameStateInfo.buffList;
  buffList = rawBuffList.map(
    (data) =>
      new Buff(data.x, data.y, data.r, data.color, data.type, data.duration)
  );

  shape = gameStateInfo.shape;
  baseHP = gameStateInfo.baseHP;
  currentHP = gameStateInfo.currentHP;
  invincible = gameStateInfo.invincible;
  myDirection = gameStateInfo.myDirection;
  gameState = gameStateInfo.gameState;
  commonNumber = gameStateInfo.invincible;
  bubbleNumber = gameStateInfo.bubbleNumber;
  machineNumber = gameStateInfo.machineNumber;
  chargeNumber = gameStateInfo.chargeNumber;
  tankNumber = gameStateInfo.tankNumber;
  boomNumber = gameStateInfo.boomNumber;
  trapNumber = gameStateInfo.trapNumber;
  missileNumber = gameStateInfo.missileNumber;
  $(".action-box").show();
  $(".action").show();
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  canvas.style.backgroundColor = "#000000";
  $("#score").text(score);
  $("#grade").text(grade);
  changeBlood();
  changeExp();
  drawFrame();
  changeGameState(2);
} else {
  changeGameState(0);
}
